package com.mapproject.industrymap.utils;

import org.apache.commons.dbcp.BasicDataSource;
import org.gdal.gdal.gdal;
import org.gdal.ogr.*;
import org.springframework.jdbc.core.JdbcTemplate;

public class DataItemGeojson {
    //Geojson存入PostGIS  20230112 BY  WGC
    public String GeojsonToPG(String tableName,String fileName,String strVectorFile){
        //ogr.RegisterAll();
        String resultinfo="";
        gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
        gdal.SetConfigOption("DXF_ENCODING","UTF-8");
        gdal.SetConfigOption("SHAPE_ENCODING", "");
        gdal.SetConfigOption("DXF_ENCODING", "ASCII"); //设置DXF缺省编码
        ogr.RegisterAll();

        //读取数据，这里以GeoJSON文件为例
        String strDriverName = "GeoJSON";

        //创建一个文件，根据strDriverName扩展名自动判断驱动类型
        Driver oDriver =ogr.GetDriverByName(strDriverName);
        if (oDriver == null) {
            System.out.println(strDriverName+ " 驱动不可用！\n");
            return resultinfo;
        }
        DataSource ds = oDriver.Open(strVectorFile);

        //String strVectorFile = "E:\\dxfwenjian\\49450002.dxf";
        //DataSource ds = ogr.Open(strVectorFile, 1);
        if (ds == null) {
            System.out.println("打开文件失败！");
            return resultinfo;
        }
        System.out.println("打开文件成功！");
        int iLayerCount = ds.GetLayerCount();
        System.out.println("图层数量："+iLayerCount);

        Layer jsonLayer = ds.GetLayerByIndex(0);
        Driver pgDriver = ogr.GetDriverByName("PostgreSQL");
        if (pgDriver == null) {
            System.out.println("打开驱动失败！");
            return resultinfo;
        }
        System.out.println("打开驱动成功！");

        //GDAL连接PostGIS（wgc本地参数，连服务器需要修改参数）
        String path = "PG:dbname=WJMap host=localhost port=5432 user=postgres password=lvshuangxi";
        DataSource pgDataSource = pgDriver.Open(path, 1);
        if(pgDataSource == null){
            System.out.println("GDAL连接PostGIS数据库失败!");
            return resultinfo;
        }
        //创建图层
        String pgLayerName_PL = fileName+"_PL";
        String pgLayerName_PG = fileName+"_PG";
        String pgLayerName_PT = fileName+"_PT";

        Layer pgLayer_PL = pgDataSource.CreateLayer(pgLayerName_PL,null,ogr.wkbLineString,null);
        Layer pgLayer_PG = pgDataSource.CreateLayer(pgLayerName_PG,null,ogr.wkbPolygon,null);
        Layer pgLayer_PT = pgDataSource.CreateLayer(pgLayerName_PT,null,ogr.wkbPoint,null);

        if (pgLayer_PL == null)
        {
            System.out.println("创建【" + pgLayerName_PL + "】表失败！");
            return resultinfo;
        }
        if (pgLayer_PG == null)
        {
            System.out.println("创建【" + pgLayerName_PG + "】表失败！");
            return resultinfo;
        }
        if (pgLayer_PT == null)
        {
            System.out.println("创建【" + pgLayerName_PT + "】表失败！");
            return resultinfo;
        }
        //创建字段
        FeatureDefn oDefn =jsonLayer.GetLayerDefn();
        //添加style字段
        /*FieldDefn styleFieldDefn = new FieldDefn("style",ogr.OFTString);
        oDefn.AddFieldDefn(styleFieldDefn);*/
        int iFieldCount =oDefn.GetFieldCount();
        for (int iAttr = 0; iAttr <iFieldCount; iAttr++)
        {
            FieldDefn oField =oDefn.GetFieldDefn(iAttr);
            System.out.println(oField.GetName());
            pgLayer_PL.CreateField(oField);
            pgLayer_PG.CreateField(oField);
            pgLayer_PT.CreateField(oField);
        }
       /* //添加style字段，经测试，如果直接在原FeatureDefn中添加style字段，gdal处理异常（只能存入一部分数据，且不报错），
        // 后采用在数据库先建立style字段，再填入
        FieldDefn styleFieldDefn = new FieldDefn("style",ogr.OFTString);
        pgLayer_PL.CreateField(styleFieldDefn);
        pgLayer_PG.CreateField(styleFieldDefn);
        pgLayer_PT.CreateField(styleFieldDefn);

        //添加Fcolor字段，用于存放要素的颜色20220208byWGC
        FieldDefn colorFieldDefn = new FieldDefn("Fcolor",ogr.OFTString);
        pgLayer_PL.CreateField(colorFieldDefn);
        pgLayer_PG.CreateField(colorFieldDefn);
        pgLayer_PT.CreateField(colorFieldDefn);*/

        //写入数据
        Feature oFeature = null;
        while ((oFeature = jsonLayer.GetNextFeature()) != null)
        {
            //String styStr = oFeature.GetStyleString();

            //对于地理要素集合（初步怀疑为块）炸开处理
            if (oFeature.GetGeometryRef().GetGeometryType() == ogr.wkbGeometryCollection
                    || oFeature.GetGeometryRef().GetGeometryType() == ogr.wkbGeometryCollection25D){
                Geometry mGeometry = oFeature.GetGeometryRef();
                int nGeoCount = mGeometry.GetGeometryCount();
                for(int iGeometry = 0; iGeometry<nGeoCount; iGeometry++){
                    Geometry pGeometry = mGeometry.GetGeometryRef(iGeometry);
                    Feature pFeature = copyFeature2(oFeature);
                    pFeature.SetGeometry(pGeometry);
                    writeToPGLayer(pFeature,pgLayer_PL,pgLayer_PG,pgLayer_PT);
                }
            }else {
                writeToPGLayer(oFeature,pgLayer_PL,pgLayer_PG,pgLayer_PT);
            }
            oFeature.delete();
        }
        //删除数据源
        pgDataSource.delete();
        ds.delete();
        gdal.GDALDestroyDriverManager();
        System.out.println("dxf文件导入成功！");
        System.out.println("转换成功！");

        //将数据写入personal_data_information表中
        BasicDataSource basicDataSource = new BasicDataSource();
        basicDataSource.setDriverClassName("org.postgresql.Driver");
        basicDataSource.setUrl("jdbc:postgresql://localhost:5432/WJMap");
        basicDataSource.setUsername("postgres");
        basicDataSource.setPassword("lvshuangxi");
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(basicDataSource);
        String layer_name = fileName.toLowerCase();
        String insertToPersonSql = "INSERT INTO public.personal_data_information(\n" +
                "\tname, server_url, layer_name, person_name, department_name, layer_style)\n" +
                "\tVALUES ('"+tableName+"', 'http://localhost:8080/geoserver/WJMap/wms', 'WJMap:"+layer_name+"', '吴国超', '空间信息所', 'polygon');";
        jdbcTemplate.execute(insertToPersonSql);

        resultinfo=fileName;
        return resultinfo;
    }

    public void writeToPGLayer(Feature oFeature,Layer pgLayer_PL,Layer pgLayer_PG,Layer pgLayer_PT){
        //实际测试中发现，导出的数据类型GetGeometryType中有多种不常见类型，还没找到很好的方法，这里直接枚举，
        // 在强制转换中，个别要素会报错（目前忽略），只处理了点线面，文字还未处理。20211208
        //20211213做了一些优化，分点线面转换，同时处理了fid重复问题，针对地形测试全部转出
        //块炸开以及多要素拆分过程中是新建的Feature，所以数据库中没有其他属性值，需优化
        //20211216新建Feature的属性值已经带入，样式字符串也存入了数据表中（style）
        if (oFeature.GetGeometryRef().GetGeometryType() == ogr.wkbPoint
                || oFeature.GetGeometryRef().GetGeometryType() == ogr.wkbPoint25D){

            Feature pPointFeature = copyFeature2(oFeature);
            int fid = pgLayer_PT.GetFeatureCount()+1;
            pPointFeature.SetFID(fid);
            pPointFeature.SetGeometry(oFeature.GetGeometryRef());
            pgLayer_PT.CreateFeature(pPointFeature);
        }else if (oFeature.GetGeometryRef().GetGeometryType() == ogr.wkbPolygon
                || oFeature.GetGeometryRef().GetGeometryType() == ogr.wkbPolygon25D) {

            Feature pPolygonFeature = copyFeature2(oFeature);
            int fid = pgLayer_PG.GetFeatureCount()+1;
            pPolygonFeature.SetFID(fid);
            pPolygonFeature.SetGeometry(oFeature.GetGeometryRef());
            pgLayer_PG.CreateFeature(pPolygonFeature);
        }else if (oFeature.GetGeometryRef().GetGeometryType() == ogr.wkbMultiPolygon
                || oFeature.GetGeometryRef().GetGeometryType() == ogr.wkbMultiPolygon25D){

            Geometry mPolygon = ogr.ForceToMultiPolygon(oFeature.GetGeometryRef());
            int nGeoCount = mPolygon.GetGeometryCount();
            for(int iPolygon = 0; iPolygon<nGeoCount; iPolygon++){
                Geometry pPolygonGeometry = mPolygon.GetGeometryRef(iPolygon);
                Feature pPolygonFeature = copyFeature2(oFeature);
                pPolygonFeature.SetGeometry(pPolygonGeometry);
                int fid = pgLayer_PG.GetFeatureCount()+1;
                pPolygonFeature.SetFID(fid);
                pgLayer_PG.CreateFeature(pPolygonFeature);
            }
        }else if (oFeature.GetGeometryRef().GetGeometryType() == ogr.wkbLineString
                || oFeature.GetGeometryRef().GetGeometryType() == ogr.wkbLineString25D){

            Feature pLineFeature = copyFeature2(oFeature);
            int fid = pgLayer_PL.GetFeatureCount()+1;
            pLineFeature.SetFID(fid);
            pLineFeature.SetGeometry(oFeature.GetGeometryRef());
            pgLayer_PL.CreateFeature(pLineFeature);
        }else if (oFeature.GetGeometryRef().GetGeometryType() == ogr.wkbMultiLineString
                || oFeature.GetGeometryRef().GetGeometryType() == ogr.wkbMultiLineString25D){

            Geometry mLine = ogr.ForceToMultiLineString(oFeature.GetGeometryRef());
            int nGeoCount = mLine.GetGeometryCount();
            for(int iLine = 0; iLine<nGeoCount; iLine++){
                Geometry pLineGeometry = mLine.GetGeometryRef(iLine);
                Feature pLineFeature = copyFeature2(oFeature);
                pLineFeature.SetGeometry(pLineGeometry);
                int fid = pgLayer_PL.GetFeatureCount()+1;
                pLineFeature.SetFID(fid);
                pgLayer_PL.CreateFeature(pLineFeature);


            }
        }else {
            System.out.println(oFeature.GetGeometryRef().GetGeometryType());
        }

    }

    public  Feature copyFeature2(Feature targetFeature){
        Feature pFeature = new Feature(targetFeature.GetDefnRef());
        int iFeatureFieldCount = targetFeature.GetFieldCount();
        for (int i=0;i<iFeatureFieldCount;i++){
            pFeature.SetField(i,targetFeature.GetFieldAsString(i));
        }
        return pFeature;
    }
    public Feature copyFeature(Feature targetFeature){
        //如果本身的Feature没有style，则用父Feature的style
        String styStr = targetFeature.GetStyleString();

        //从styStr中截取出颜色字符串
        String colorStr = GetColorFromStyStr(styStr);

        //新建字段并赋值
        FeatureDefn fDefn = new FeatureDefn();
        FieldDefn layerFieldDefn = new FieldDefn("layer",ogr.OFTString);
        FieldDefn subClassesFieldDefn = new FieldDefn("SubClasses",ogr.OFTString);
        FieldDefn extendedEntityFieldDefn = new FieldDefn("ExtendedEntity",ogr.OFTString);
        FieldDefn linetypeFieldDefn = new FieldDefn("Linetype",ogr.OFTString);
        FieldDefn entityHandleFieldDefn = new FieldDefn("EntityHandle",ogr.OFTString);
        FieldDefn textFieldDefn = new FieldDefn("Text",ogr.OFTString);
        FieldDefn styleFieldDefn = new FieldDefn("style",ogr.OFTString);
        FieldDefn colorFieldDefn = new FieldDefn("Fcolor",ogr.OFTString);
        fDefn.AddFieldDefn(layerFieldDefn);
        fDefn.AddFieldDefn(subClassesFieldDefn);
        fDefn.AddFieldDefn(extendedEntityFieldDefn);
        fDefn.AddFieldDefn(linetypeFieldDefn);
        fDefn.AddFieldDefn(entityHandleFieldDefn);
        fDefn.AddFieldDefn(textFieldDefn);
        fDefn.AddFieldDefn(styleFieldDefn);
        fDefn.AddFieldDefn(colorFieldDefn);
        Feature pFeature = new Feature(fDefn);
        pFeature.SetField("layer",targetFeature.GetFieldAsString("layer"));
        pFeature.SetField("SubClasses",targetFeature.GetFieldAsString("SubClasses"));
        pFeature.SetField("ExtendedEntity",targetFeature.GetFieldAsString("ExtendedEntity"));
        pFeature.SetField("Linetype",targetFeature.GetFieldAsString("Linetype"));
        pFeature.SetField("EntityHandle",targetFeature.GetFieldAsString("EntityHandle"));
        pFeature.SetField("Text",targetFeature.GetFieldAsString("Text"));
        pFeature.SetField("style",styStr);
        pFeature.SetField("Fcolor",colorStr);
        return pFeature;
    }
    //从styStr中截取出颜色字符串
    public String GetColorFromStyStr(String styStr){
        //预定义colorStr为#000000（黑色）
        String colorStr = "#000000";
        if(styStr == null || styStr ==""){
            return "#000000";
        }
        int firstIndex = styStr.indexOf('('); //找到第一个(所在位置
        int lastIndex = styStr.lastIndexOf(')'); //找到最后一个)所在位置

        String title = styStr.substring(0,firstIndex);
        //根据样式类型不同，分别处理。
        //注：测试用，粗糙处理，实际上项目特别容易出现BUG，需要优化
        switch (title){
            case "PEN" :
                colorStr = styStr.substring(6,13);
                break;
            case "LABEL" :
                colorStr = styStr.substring(styStr.length()-8,styStr.length()-1);
                break;
        }
        //优化1：将所有的白色#ffffff全部替换为黑色#000000，因为背景是白色
        if (colorStr=="#ffffff"){colorStr = "#000000";}
        return colorStr;

    }

}
